
// <copyright file="GenericPool.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The generic pool.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Pooling
{
    using System;

    /// <summary>
    /// The generic pool.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public class GenericPool<T> : AbstractPool<T, GenericPoolItem<T>>
        where T : new()
    {
        #region Fields

        /// <summary>
        /// The strategy.
        /// </summary>
        private readonly IAdaptedObjectSelectionStrategy<T> _strategy;

        #endregion Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes a new instance of the <see cref="GenericPool{T}"/> class.
        /// </summary>
        /// <param name="strategy">
        /// The strategy.
        /// </param>
        public GenericPool(IAdaptedObjectSelectionStrategy<T> strategy = null)
        {
            this._strategy = strategy;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GenericPool{T}"/> class.
        /// </summary>
        /// <param name="maxPoolSize">
        /// The max pool size.
        /// </param>
        /// <param name="objectMaxIdleTimeInMilliseconds">
        /// The object max idle time in milliseconds.
        /// </param>
        /// <param name="canObjectBeShared">
        /// The can object be shared.
        /// </param>
        /// <param name="strategy">
        /// The strategy.
        /// </param>
        public GenericPool(int maxPoolSize, int objectMaxIdleTimeInMilliseconds, bool canObjectBeShared, IAdaptedObjectSelectionStrategy<T> strategy = null)
            : base(maxPoolSize, objectMaxIdleTimeInMilliseconds, canObjectBeShared)
        {
            this._strategy = strategy;
        }

        #endregion Constructors and Finalizers

        #region Public Methods and Operators

        /// <summary>
        /// The begin get object.
        /// </summary>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public IAsyncResult BeginGetObject()
        {
            return this.beginGetObject(null);
        }

        /// <summary>
        /// The begin try get object.
        /// </summary>
        /// <param name="millisecondsToWait">
        /// The milliseconds to wait.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        public IAsyncResult BeginTryGetObject(int millisecondsToWait)
        {
            return this.beginTryGetObject(null, millisecondsToWait);
        }

        /// <summary>
        /// The end get object.
        /// </summary>
        /// <param name="result">
        /// The result.
        /// </param>
        /// <returns>
        /// The <see cref="GenericPoolItem"/>.
        /// </returns>
        public GenericPoolItem<T> EndGetObject(IAsyncResult result)
        {
            return this.endGetObject(result);
        }

        /// <summary>
        /// The end try get object.
        /// </summary>
        /// <param name="result">
        /// The result.
        /// </param>
        /// <param name="obj">
        /// The obj.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool EndTryGetObject(IAsyncResult result, out GenericPoolItem<T> obj)
        {
            return this.endTryGetObject(result, out obj);
        }

        /// <summary>
        /// The get object.
        /// </summary>
        /// <returns>
        /// The <see cref="GenericPoolItem"/>.
        /// </returns>
        public GenericPoolItem<T> GetObject()
        {
            return this.getObject(null);
        }

        /// <summary>
        /// The try get object.
        /// </summary>
        /// <param name="obj">
        /// The obj.
        /// </param>
        /// <param name="millisecondsToWait">
        /// The milliseconds to wait.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool TryGetObject(out GenericPoolItem<T> obj, int millisecondsToWait)
        {
            return this.tryGetObject(out obj, null, millisecondsToWait);
        }

        #endregion Public Methods and Operators

        #region Methods

        /// <summary>
        /// The can select this adaptedObject.
        /// </summary>
        /// <param name="adaptedObject">
        /// The adaptedObject.
        /// </param>
        /// <param name="isNewlyCreatedAdaptedObject">
        /// The is newly created adaptedObject.
        /// </param>
        /// <param name="tag">
        /// The tag.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        protected override bool canSelectThisAdaptedObject(T adaptedObject, bool isNewlyCreatedAdaptedObject, object tag)
        {
            if (this._strategy != null)
            {
                return true;

                // _strategy.CanSelectThisAdaptedObject(AdaptedObjectProtected, isNewlyCreatedAdaptedObject, tag);
            }

            return base.canSelectThisAdaptedObject(adaptedObject, isNewlyCreatedAdaptedObject, tag);
        }

        /// <summary>
        /// The get adaptedObject.
        /// </summary>
        /// <returns>
        /// The <see cref="T"/>.
        /// </returns>
        protected override T getAdaptedObject()
        {
            return new T();
        }

        #endregion Methods
    }
}
